﻿using System.Collections;
using System.Collections.Generic;
using System.Linq;
using DG.Tweening;
using Gp.Scripts.Character;
using Gp.Scripts.Core.Skill;
using Gp.Scripts.Data.Skills;
using Helpers;
using Pathfinding;
// using Pathfinding;
using Pathfinding.Util;
using UnityEngine;
using Vector3 = UnityEngine.Vector3;

namespace Gp.Scripts.Core
{
    public class MoveSkillEntity : SkillEntity
    {
        public override IEnumerator Act(SkillContext context)
        {
            // if (context is not GroundSelectContext gc) yield break;

            // yield return WalkTo(context.ClickPosition);
            if (context.Get<List<Vector3>>("Path") is { } path)
            {
                // yield return WalkTo()
                // 路径移动
            }
            else if (context.TargetCell.Node is not null)
            {
                yield return WalkTo(context.TargetCell);
            }
        }


        protected override void OnInit()
        {
        }


        // public void ExecuteMove(Vector3 destination) {
        //     // HumanExecute();
        // }


        // public IEnumerator DashTo(Vector3 destination, int maxDistance = int.MaxValue) {
        //     var finalMovePos = destination;
        //     var source = UnitReference.transform.position;
        //     var distance = Vector3.Distance(source, destination);
        //     if (distance > maxDistance) {
        //         finalMovePos = source + (destination - source).normalized * maxDistance;
        //     }
        //     // finalMovePos = 
        //     NavHelper.SamplePosition(finalMovePos, out finalMovePos);
        //     UnitReference.transform.DOPunchPosition(Vector3.back * .1f, .05f);
        //     UnitReference.Model.GestureTrigger(new MoveGestureTrigger(finalMovePos));
        //     
        //     yield return new WaitForSeconds(.05f);
        //     UnitReference.transform.DOMove(finalMovePos, .5f);
        //     yield return new WaitForSeconds(.55f);
        //     yield break;
        // }
        //


        public IEnumerator WalkTo(VBattleCell destinationCell, int maxMoveDistance = int.MaxValue)
        {
            var path = Global.Get<BattleSystem>().CellGrid.ConstructPath(UnitReference, destinationCell);

            yield return path.WaitForPath();
            if (path.error) yield break;


            Vector3           selfPos     = UnitReference.transform.position;
            List<Vector3>     orgPath     = path.VectorPath;
            List<Vector3>     resMovePath = new() {selfPos};
            List<VBattleCell> battleCells = path.VCells;

            // 处理超出移动距离的情况
            // 截去超出范围的部分
            float distanceSum = 0;
            for (int i = 1; i < orgPath.Count; i++)
            {
                Vector3 p1       = orgPath[i], p2 = orgPath[i - 1];
                Vector3 dis      = p1 - p2;
                float   pointLen = dis.magnitude;

                if (distanceSum + pointLen <= maxMoveDistance)
                {
                    distanceSum += pointLen;
                    resMovePath.Add(p1);
                    continue;
                }

                // 截取长度
                var cutLen = maxMoveDistance - distanceSum;

                // 截取大于该点之后的部分
                resMovePath.Add(p2 + (dis * (cutLen / pointLen)));
                break;
            }

            resMovePath = CatmullRomSmoothPath(resMovePath);
            DrawDebugLines(resMovePath, battleCells);

            yield return WalkTo(resMovePath, battleCells);
        }

        private void DrawDebugLines(List<Vector3> walkPath, List<VBattleCell> walkCells)
        {
            for (var i = 1; i < walkPath.Count; i++)
            {
                Debug.DrawLine(walkPath[i], walkPath[i - 1], Color.cyan, 5);
            }

            foreach (var cell in walkCells)
            {
                Debug.DrawLine(cell.Position, cell.Position + Vector3.up, Color.yellow, 5);
            }
        }

        private List<Vector3> CatmullRomSmoothPath(List<Vector3> path)
        {
            // SimpleSmoothModifier smoothModifier = new SimpleSmoothModifier();
            // if (smoothModifier.subdivisions < 0) smoothModifier.subdivisions = 0;

            int           subMult    = 1;
            List<Vector3> subdivided = ListPool<Vector3>.Claim();

            for (int i = 0; i < path.Count - 1; i++)
            {
                var p0 = path[Mathf.Max(i - 1, 0)];
                var p1 = path[i];
                var p2 = path[i + 1];
                var p3 = path[Mathf.Min(i + 2, path.Count - 1)];

                // for (int j = 0; j < subMult; j++)
                // {
                Vector3 interpolatedPoint = AstarSplines.CatmullRom(p0, p1, p2, p3, 0.5f);
                subdivided.Add(interpolatedPoint);
                // }
            }

            subdivided.Add(path[^1]);
            return subdivided;
        }

        public IEnumerator WalkTo(List<Vector3> path, List<VBattleCell> goThroughCells)
        {
            if (!UnitReference.TryGetComponent<BaseCharacter>(out var ch))
            {
                yield break;
            }

            ch.CanRun = true;
            // todo: 使用专门接口
            ch.GetCharacterAnimator().animator.SetBool(UnitAnimatorParameter.IsBattleModeBool, false);

            for (int i = 1; i < path.Count; i++)
            {
                UnitReference.TriggerEvent(new Event_Unit.Move(goThroughCells[i - 1], goThroughCells[i]));

                bool isCharacterMoving = true;
                ch.characterLocomotion.SetTarget(path[i], null, 0, () => isCharacterMoving = false);
                while (isCharacterMoving)
                {
                    yield return null;
                }
            }

            ch.GetCharacterAnimator().animator.SetBool(UnitAnimatorParameter.IsBattleModeBool, true);
        }


        public override DisableReason CanSelect()
        {
            // return base.CanPerform().And(DS_Reason.Resource,
                // () => UnitReference.ComCost.CheckResource(CostField.ShiftPoint));
                return DisableReason.True();
        }


        public override DisableReason CanExecute(SkillContext context)
        {
            return DisableReason.True();
        }

        public bool CanMove(VBattleCell cell)
        {
            return true;
        }


        public override CostWrapper SkillCostInfo()
        {
            return CostWrapper.Empty;
        }


        // public MoveSkillEntity(SkillEntityConfig config) : base(config) { }
    }
}